/*
 * Copyright (C) 2010 Sinapsi Spa
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.sinapsi.memtracker.sonar;

import static com.sinapsi.memtracker.sonar.MemTrackerMetrics.HEAP_OCCUPATION;
import static com.sinapsi.memtracker.sonar.MemTrackerMetrics.PERM_GEN_OCCUPATION;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.lang.management.MemoryType;
import java.lang.management.MemoryUsage;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.Sensor;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.resources.Project;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;

public class MemTrackerSensor implements Sensor {

    private static final long MB = 1024L * 1024L;
    private static final String DEFAULT_MEMORY_FILE = "/mem-tracker/memory-usage.xml";
    private static final Logger log = LoggerFactory.getLogger(MemTrackerSensor.class);

    public void analyse(Project project, SensorContext context) {
        String memoryFile = project.getFileSystem().getBuildDir().getAbsolutePath() + DEFAULT_MEMORY_FILE;
        if (new File(memoryFile).exists()) {
            try {
                // collect and aggregate values
                long heap = 0;
                long permGen = 0;
                List<Memory> memories = load(memoryFile);
                for (Memory memory : memories) {
                    if (memory.getType().equals(MemoryType.HEAP)) {
                        heap += memory.getMemoryUsage().getUsed();
                    }
                    if (memory.getPoolName().equals("PS Perm Gen")) {
                        permGen += memory.getMemoryUsage().getUsed();
                    }
                }
                
                // display values only if not zero
                if (heap != 0) {
                    context.saveMeasure(HEAP_OCCUPATION, Double.valueOf(heap / MB));
                }
                if (permGen != 0) {
                    context.saveMeasure(PERM_GEN_OCCUPATION, Double.valueOf(permGen/ MB));
                }
            } catch (Exception e) {
                log.error("error while reading memory from file [{}]: {}", memoryFile, e);
            }
            log.info("read memory from file [{}]", memoryFile);
        } else {
            log.warn("no memory file found at [{}]", memoryFile);
        }
    }

    public boolean shouldExecuteOnProject(Project project) {
        return true;
    }

    @SuppressWarnings("unchecked")
    public static List<Memory> load(String file) throws FileNotFoundException {
        return (List<Memory>) buildXStream().fromXML(new FileInputStream(file));
    }

    private static XStream buildXStream() {
        XStream xstream = new XStream(new DomDriver());
        xstream.alias("memory", Memory.class);
        xstream.alias("usage", MemoryUsage.class);
        xstream.alias("type", MemoryType.class);
        return xstream;
    }
}
